
#include <BRender>
#include <BMaterial>
#include <BGeoSphere>
#include "member_BGeoSphere.h"
#include "member_BMesh.h"
#include "member_BShape.h"

using namespace BWE;

#define member					(*(member_BGeoSphere*)_ptr)
#define member_allocate()		_ptr = new member_BGeoSphere(this)
#define member_release()		delete (member_BGeoSphere*)_ptr

BGeoSphere::BGeoSphere()
{
	member_allocate();
}
BGeoSphere::BGeoSphere(BReal radius)
{
	member_allocate();
	this->setRadius(radius);
}
BGeoSphere::BGeoSphere(BReal radius, int divide)
{
	member_allocate();
	this->setRadius(radius);
	this->setDivide(divide);
}
BGeoSphere::~BGeoSphere()
{
	member_release();
}

void BGeoSphere::setRadius(BReal radius)
{
	if (member.radius != radius)
	{
		member.radius = radius;
		member.dirty = true;
		this->dirty();
	}
}
BReal BGeoSphere::radius() const
{
	return member.radius;
}

void BGeoSphere::setDivide(int divide)
{
	divide = bClamp(divide, 0, 9);
	if (member.divide != divide)
	{
		member.divide = divide;
		member.dirty = true;
		this->dirty();
	}
}
int BGeoSphere::divide() const
{
	return member.divide;
}

BMesh* BGeoSphere::split(int id)
{
	if (id < 0 || id > 19)
		return 0;
	this->flush();
	BMesh* mesh = new BMesh();
	mesh->copy(this);

	BVectorArray* vertices = new BVectorArray();
	vertices->append(mesh_member(this)->vertices->data() + member.stride* id, member.stride);
	mesh->setVertices(vertices);

	BVectorArray* normals = new BVectorArray();
	normals->append(mesh_member(this)->normals->data() + member.stride * id, member.stride);
	mesh->setNormals(normals);

	int faceStride = member.segment * member.segment;
	BFaceArray* faces = new BFaceArray();
	faces->append(mesh_member(this)->faces->data() + faceStride * id, faceStride);
	mesh->setFaces(faces);

	for (int i = 0; i < mesh_member(this)->coords.size(); i++)
	{
		if (mesh_member(this)->coords[i].valid())
		{
			BCoordArray* coords = new BCoordArray(member.stride);
			coords->append(mesh_member(this)->coords[i]->data() + member.stride * id, member.stride);
			mesh->setTexCoords(coords, i);
		}
	}

	if (mesh_member(this)->colors->size())
	{
		BColorArray* colors = new BColorArray(member.stride);
		colors->append(mesh_member(this)->colors->data() + member.stride * id, member.stride);
		mesh->setColors(colors);
	}
	return mesh;
}

void BGeoSphere::refresh(BBox& box)
{
	if (member.dirty)
	{
		member.rebuild();
		member.dirty = false;
	}
	BSpace space;
	space.min() = BVector(-member.radius, -member.radius, -member.radius);
	space.max() = BVector(member.radius, member.radius, member.radius);
	box = space;
}
